home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Just Call Me Internet
/
Just Call Me Internet.iso
/
prog
/
atari
/
c
/
snz128s
/
src
/
unbatch.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-06-18
|
40KB
|
1,376 lines
/*
SNEWS 2.00
unbatch - quick and dirty news toss, no feeding of other sites
Copyright (C) 1991 John McCombs, Christchurch, NEW ZEALAND
john@ahuriri.gen.nz
PO Box 2708, Christchurch, NEW ZEALAND
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License, version 1, as
published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
See the file COPYING, which contains a copy of the GNU General
Public License.
USAGE: unbatch {[-a] [-n] [-v] [-i] [-j] [-f] [-l] [-s] [-d]}
-a means add any news groups found
-n means decompress the first batch, then stop before tossing
-v means verbose, tell what we are doing
-i means query for adding any new groups found
-j means junk, don't add to junk if posted elsewhere
-f means filter, filter out non printable characters
-l means ignore length in headers
-s means don't check for free space
-x means run Snews on successful end
-d means force unbatch to process on disk
NOTE: for the Atari version the meaning of the -f and -l switches
have been reversed.
-f means do not filter out non-printable characters
-l means do not ignore lengths in headers
I have done this because the previous action was causing
problems (bus errors) and I do not have time to investigate
why.
*/
/*---------------------------- Source Control ------------------------------*/
/*
* $Id: UNBATCH.C,v 1.2 1994/02/05 18:50:32 gbj Exp user $
*/
/****************************************************************************
* 20 May 92 1.2 GT ka9q mods. *
* 08 Jun 92 1.3 GT FQDN in "Path:". *
* Fix disc space check. *
* 09 Jun 92 1.4 GT Only expand "Path:" in header. *
* 12 Jun 92 1.5 NJL Check for duplicate articles; add verbose mode; *
* restructure toss(); improve performance; *
* slightly improve #!rnews test. *
* 24 Jun 92 1.6 GT Ensure that spool_file is open in toss (). *
* 17 Jul 92 1.7 GT C++ compilation. *
* 27 Jul 92 1.8 MSM Add -j option, only post to junk if not posted *
* elsewhere. *
* Change file I/O to binary, to allow for ^Z. *
* Add -f option to filter non printable chars. *
* 16 Aug 92 1.9 MSM Snews 1.9 *
* Add article count to verbose display *
* Check / Process lock files *
* rfc1036 style header accepted, but not used *
* use tmp/temp environemnt variable for spool *
* file. *
* 27 Aug 92 1.10 MSM Fix long newsgroup header line breaking unbatch *
* Fix disk free check to check the drive newsbase *
* the newsbase resides on, not the default drive. *
* 26 Sep 92 1.11 MSM Detect and place in control group any article *
* with a control header. *
* 27 Nov 92 1.12 MSM Article Length display, clean up lock file on *
* exits. *
* 29 Dec 92 1.13 MSM Save startup environment. *
* Check article length when available but add -l *
* flag to disable checks. *
* Add new groups found in newsbatches to newsbase *
* Clean up exit when history.snw not found *
* Change option messages *
* Make checking of free space optional *
* 1 Feb 93 1.14 MSM Change code to access temporary files *
* 22 Feb 93 1.15 MSM Wrong verbose article length fixed *
* 31 May 93 1.16 MSM Snews 2.0 *
* Fix prescan for new groups picking up from body *
* In memory article extraction *
* Tidy up *
* Large article processing to disk *
* 10 Jul 93 1.17 MSM Correct assumption about memory overhead *
* Read only first Newsgroups: line *
* (as requested by G.Toal) *
* 1 Sep 93 1.18 MSM Add use disk option and history full warning *
* 5 Sep 93 1.19 MSM Atexit added *
* 10 Oct 93 1.20 MSM Truncate long (illegal) subject lines *
* 18 oct 93 1.21 MSM Long integer handling tidied up *
* Return codes added *
* Load failure due to size of history only *
* reported if verbose mode is on. *
* 5 Dec 93 1.22 MSM Subject limited to 128 characters *
* 9 Dec 93 1.23 MSM Error reporting code added *
* 2 Apr 94 1.24 MSM Delete all lock files on error exits *
* Account for use of memory by history list when *
* unbatching articles *
* 11 Jun 94 AT GBJ Reverse meaning of -l -f switches *
****************************************************************************/
#include <ctype.h>
#include <fcntl.h>
#include <io.h>
#include <process.h>
#ifdef __TURBOC__
# include <dir.h>
#else
# ifdef ATARI
# include <sys/dir.h>
# include <stdlib.h>
# include <ext.h>
# include <errno.h>
# else
# include <direct.h>
# endif
#endif
#include "defs.h"
#include "unbatch.h"
#include "locking.h"
#ifndef __TURBOC__
#ifndef ATARI
unsigned long farcoreleft(void);
unsigned long testcoreleft(void);
#define ffblk _find_t
#define ff_reserved reserved
#define ff_attrib attrib
#define ff_ftime wr_time
#define ff_date wr_date
#define ff_size size
#define ff_name name
#define findfirst(a, b, c) _dos_findfirst(a, c, b)
#define findnext _dos_findnext
#define getdfree _dos_getdiskfree
#define df_avail avail_clusters
#define df_total total_clusters
#define df_bsec bytes_per_sector
#define df_sclus sectors_per_cluster
#endif
#endif
#ifndef ATARI
int getopt(int argc, char **argv, char *opts);
#endif
#ifdef ATARI
extern unsigned long _STACK = 32768;
int statx(const char *, struct stat *);
#else
unsigned _stklen = 16384;
#endif
INFO my_stuff;
/* There are far too many statics here, it needs sorting out ! */
static char buf[512], msg[256], subject[256], msg_id[256];
static char newsgroups[512];
static time_t t;
#ifdef ATARI
static char *Usage = "\
Usage: unbatch [-a] [-d] [-f] [-i] [-j] [-l] [-n] [-s] [-v] [-x]\n\
a = add automatically any new groups found in news batch\n\
d = process via disk\n\
f = do not filter out non printable characters\n\
i = add interactivly any new groups found in news batch\n\
j = don't add to junk if posted elsewhere\n\
l = check article length\n\
n = no unpacking to newsbase (test mode)\n\
s = do not check for free space before unbatching\n\
v = verbose mode\n\
x = execute Snews on exit\n\n";
#else
static char *Usage = "\
Usage: unbatch [-a] [-d] [-f] [-i] [-j] [-l] [-n] [-s] [-v] [-x]\n\
a = add automatically any new groups found in news batch\n\
d = process via disk\n\
f = filter out non printable characters\n\
i = add interactivly any new groups found in news batch\n\
j = don't add to junk if posted elsewhere\n\
l = don't check article length\n\
n = no unpacking to newsbase (test mode)\n\
s = do not check for free space before unbatching\n\
v = verbose mode\n\
x = execute Snews on exit\n\n";
#endif
static char verbose = 0;
static char cixmode = 0;
static char CrossPostToJunk = 1;
static char batch_name[65] = {""};
static char spool_name[65];
static unsigned int article_count = 0;
static unsigned int duplicate_count = 0;
static unsigned int junk_count = 0;
#ifdef ATARI
static unsigned int filter_mode = 1;
#else
static unsigned int filter_mode = 0;
#endif
#ifdef ATARI
static unsigned int no_length = 1;
#else
static unsigned int no_length = 0;
#endif
static unsigned int control_flag = 0;
static unsigned long art_length = 0l;
static unsigned long prev_art_length = 0l;
static unsigned long art_start = 0l;
static unsigned long art_end = 0l;
static unsigned long art_end_calc = 0l;
static unsigned long art_lines = 0l;
static unsigned int interactive_add = 0;
static unsigned int add_all = 0;
static unsigned int space_mode = 0;
static unsigned int Exec_Snews = 0;
static unsigned long Free_Mem;
static unsigned int disk_cnt = 0;
static unsigned long MinFree = 0l;
static unsigned long MaxFree = 0l;
static unsigned long LargestArt = 0l;
static int Via_Disk = 0;
#ifdef ATARI
extern char **environ; /* the environment */
#endif
/*------------------------------- main --------------------------------*/
int main(int argc, char *argv[])
{
FILE *tmp_file, *spool_file;
static char name[256], in_name[256];
int ans, done, no_toss = 0;
#ifndef ATARI
int drive;
#else
dev_t drive;
char drive_letter[]="?ABCDEFGHIJKLMNOPQRSTUVWXYZ";
long disk_total;
#endif
long required_disk, disk_free;
struct stat st;
#ifdef __TURBOC__
struct dfree df;
#else
#ifdef ATARI
struct dfree df;
#else
struct _diskfree_t df;
#endif
#endif
struct ffblk ffblk;
int c;
int ret_code;
if (fprintf(stderr, "Demon Internet Simple News v%d.%02d [build %d]\n",
rmj, rmm, rup) == EOF)
abort_error(1, "");
fprintf(stderr, "Unbatch New News\n\n");
atexit(end_stats);
Free_Mem = farcoreleft();
MinFree = MaxFree = Free_Mem;
while ((c = getopt(argc, argv, "aAdDfFiIjJlLsSnNvVxX?")) != EOF)
switch (tolower(c)) {
case 'a':
/* add mode */
add_all = 1;
interactive_add = 0;
fprintf(stderr, "\tAll new Newsgroups will be added.\n");
break;
case 'd':
/* disk mode */
Via_Disk = 1;
fprintf(stderr, "\tProcessing will be forced via disk.\n");
break;
case 'f':
/* Filter mode */
#ifdef ATARI
filter_mode = 0;
fprintf(stderr, "\tNon printing characters will not be removed.\n");
#else
filter_mode = 1;
fprintf(stderr, "\tNon printing characters will be removed.\n");
#endif
break;
case 'i':
/* Interactive add new groups */
interactive_add = 1;
add_all = 0;
fprintf(stderr, "\tNew Newsgroups will be added interactively.\n");
break;
case 'l':
/* if TRUE then don't test article lengths */
#ifdef ATARI
no_length = 0;
fprintf(stderr, "\tArticle length will be checked.\n");
#else
no_length = 1;
fprintf(stderr, "\tArticle length will not be checked.\n");
#endif
break;
case 'n':
/* if TRUE, then just uncompress, don't unbatch */
no_toss = 1;
fprintf(stderr, "\tUncompress pass only will be run.\n");
break;
case 's':
/* free space mode */
space_mode = 1;
fprintf(stderr, "\tFree space will not be checked.\n");
break;
case 'v':
/* Verbose mode */
verbose = 1;
fprintf(stderr, "\tProgress will be reported verbosely.\n");
break;
case 'c':
/* cix mode - no #!rnews separators (not yet implemented) */
cixmode = 1;
fprintf(stderr, "\tCIX mode is set on.\n");
break;
case 'j':
/* Junk Mode - crosspost to junk supressed */
CrossPostToJunk = 0;
fprintf(stderr, "\tArticles will not be crossposted to Junk.\n");
break;
case 'x':
/* Execute Snews on exit */
Exec_Snews = 1;
fprintf(stderr, "\tSnews will be run on successful completion.\n");
break;
case '?':
fprintf(stderr, Usage);
exit(1);
}
if (!load_stuff()) {
fprintf(stderr, "unbatch: Couldn't read rc info\n");
exit(1);
}
sprintf(in_name, "%s*.lck", my_stuff.incoming_dir);
done = findfirst(in_name, &ffblk, 0);
if (!done) {
fprintf(stderr, "unbatch: Article file(s) locked!\n");
exit(1);
}
sprintf(in_name, "%shistory.lck", my_stuff.news_dir);
done = findfirst(in_name, &ffblk, 0);
if (!done) {
fprintf(stderr, "unbatch: History file locked!\n");
exit(1);
}
sprintf(in_name, "%s*.*", my_stuff.incoming_dir);
done = findfirst(in_name, &ffblk, 0);
strcpy(batch_name, ffblk.ff_name);
while (!done) {
if (mlock(my_stuff.incoming_dir, ffblk.ff_name, "Unbatch") != 0) {
/* Fudge to avoid processing or complaining about .lck files */
if (strstr(ffblk.ff_name, ".LCK") == NULL)
fprintf(stderr, "unbatch: Can't lock article file %s%s\n",
my_stuff.incoming_dir, ffblk.ff_name);
done = findnext(&ffblk);
}
else
break;
}
if (done) {
fprintf(stderr, "unbatch: Nothing to process!\n");
if (Exec_Snews == 1) {
fprintf(stderr, "\n\nLoading Snews ....\n");
#ifdef ATARI
ans = forklpe("snews", "snews", NULL, environ);
#else
ans = execlp("snews", "snews", NULL);
#endif
fprintf(stderr, "unbatch: exec error %d\n", ans);
}
exit(1);
}
if (add_all != 0) /* add new groups ? */
proc_new(ffblk.ff_name, 1);
if (interactive_add != 0)
proc_new(ffblk.ff_name, 2);
if (mlock(my_stuff.news_dir, "history", "Unbatch") != 0) {
fprintf(stderr, "unbatch: Can't lock history file!\n");
rmlock(my_stuff.incoming_dir, ffblk.ff_name, "Unbatch");
exit(1);
}
load_active_file();
free_ng();
sprintf(name, "%shistory.snw", my_stuff.news_dir);
if ((tmp_file = fopen(name, "rb")) == NULL) {
fprintf(stderr, "\n\rHistory file not found, create one (y/n) ? ");
ans = getch();
putch(ans);
putch('\n');
putch('\r');
ans = tolower(ans);
if (ans != 'y') {
fprintf(stderr, "unbatch: No history file!\n");
rmlock(my_stuff.incoming_dir, ffblk.ff_name, "Unbatch");
rmlock(my_stuff.news_dir, "History", "Unbatch");
exit(1);
}
tmp_file = fopen(name, "wb");
if (tmp_file == NULL) {
fprintf(stderr, "unbatch: Unable to create history file!\n");
rmlock(my_stuff.incoming_dir, ffblk.ff_name, "Unbatch");
rmlock(my_stuff.news_dir, "History", "Unbatch");
exit(1);
}
}
if (fclose(tmp_file) == EOF)
abort_error(2, "Closing history.snw");
load_history_list(0);
Free_Mem = farcoreleft();
if ((Free_Mem < HIST_MEM_LIMIT) && (verbose == 1)) {
fprintf(stderr, "unbatch: Insufficient memory to load entire history\n");
fprintf(stderr, " duplicate articles may not be detected. Proceed (y/n) ? ");
ans = getch();
ans = toupper(ans);
putch(ans);
putch('\n');
putch('\r');
if (ans != 'Y') {
rmlock(my_stuff.incoming_dir, ffblk.ff_name, "Unbatch");
rmlock(my_stuff.news_dir, "History", "Unbatch");
exit(1);
}
}
MinFree = Free_Mem;
MaxFree = Free_Mem;
Free_Mem = ((Free_Mem) / 3l);
if (Free_Mem < 16384l) {
fprintf(stderr, "unbatch: Insufficient memory available!\n");
rmlock(my_stuff.incoming_dir, ffblk.ff_name, "Unbatch");
rmlock(my_stuff.news_dir, "History", "Unbatch");
exit(1);
}
sprintf(spool_name, "%s\\$$item", my_stuff.temp_name);
if ((spool_file = fopen(spool_name, "w+b")) == NULL) {
fprintf(stderr, "unbatch: Unable to create temporary file!\n");
rmlock(my_stuff.incoming_dir, ffblk.ff_name, "Unbatch");
rmlock(my_stuff.news_dir, "History", "Unbatch");
exit(1);
}
if (fclose(spool_file) == EOF) /* we may never use it ! */
abort_error(3, "Closing temporary spool file");
if (unlink(spool_name) != 0)
abort_error(4, "Deleting temporary spool file");
while (!done) {
sprintf(name, "%s%s", my_stuff.incoming_dir, ffblk.ff_name);
fprintf(stderr, "unbatch: processing %s\n", name);
/*
* Check for enough room. We need:
*
* - more than twice the size of the batch for uncompressed batch,
* say 1.2 * space for the articles.
*
* For example a 100k batch may require 280kb for the uncompressed
* batch, then another 280 kb for the articles.
*
* Of course the above does not apply to non-compressed batches
* I reckon 1.2 times the size should do, allowing for slack.
*/
if (space_mode == 0) {
if (statx(name, &st) != 0)
abort_error(5, "Determining drive status");
required_disk = (long)((float) st.st_size * 1.2);
strcpy(name, getenv("SNEWS"));
if (strlen(name) > 3) {
if (name[strlen(name)-1] == '\\')
name[strlen(name)-1] = '\0';
}
strcat(name, "\\snews.rc");
if(statx(name, &st) != 0)
abort_error(6, "Determine drive status");
drive = st.st_dev;
getdfree(drive + 1, &df);
if (df.df_sclus == 0xffff)
abort_error(7, "Determine disk space");
disk_free = (long) df.df_avail * (long) df.df_bsec *
(long) df.df_sclus;
#ifdef ATARI
disk_total = (long)df.df_total * (long)df.df_bsec *
(long)df.df_sclus;
printf("unbatch: Drive %c: avail %ldK, total %ldK\n",
drive_letter[st.st_dev+1], disk_free/1024, disk_total/1024);
#endif
if (disk_free < required_disk) {
fprintf(stderr, "unbatch: %ld bytes of disk req'd to unpack batch\n",
required_disk);
fprintf(stderr, "unbatch: only %ld bytes of disk space available\n",
disk_free);
rmlock(my_stuff.incoming_dir, ffblk.ff_name, "Unbatch");
rmlock(my_stuff.news_dir, "History", "Unbatch");
exit(1);
}
}
/* uncompress the news batch and return a pointer to the temp file */
sprintf(name, "%s%s", my_stuff.incoming_dir, ffblk.ff_name);
if ((tmp_file = decode_batches(name, no_toss)) != NULL) {
open_hist_file();
toss(tmp_file);
close_hist_file();
fclose(tmp_file);
if (unlink(name) != 0) {
sprintf(buf, "deleting file %s", name);
abort_error(8, buf);
}
sprintf(name, "%s\\$$item", my_stuff.temp_name);
unlink(name);
}
else {
fprintf(stderr, "unbatch: could not unpack compressed news batch %s\n", name);
rmlock(my_stuff.incoming_dir, ffblk.ff_name, "Unbatch");
rmlock(my_stuff.news_dir, "History", "Unbatch");
exit(1);
}
rmlock(my_stuff.incoming_dir, ffblk.ff_name, "Unbatch");
while ((done = findnext(&ffblk)) == 0) {
if (mlock(my_stuff.incoming_dir, ffblk.ff_name, "Unbatch") != 0) {
/* Fudge to avoid processing or complaining about .lck files */
if (strstr(ffblk.ff_name, ".LCK") == NULL)
fprintf(stderr, "unbatch: Unable to lock article file %s%s\n",
my_stuff.incoming_dir, ffblk.ff_name);
}
else
break;
}
}
close_active_file();
free_hist_list();
rmlock(my_stuff.news_dir, "history", "Unbatch");
if (Exec_Snews == 1) {
fprintf(stderr, "\n\nLoading Snews ....\n");
#ifdef ATARI
ans = forklpe("snews", "snews", NULL, environ);
#else
ans = execlp("snews", "snews", NULL);
#endif
fprintf(stderr, "unbatch: exec error %d\n", ans);
}
ret_code = 0;
return ret_code;
}
/*---------------------------- Error Handler -------------------------------*/
void abort_error(int numb, char *text)
{
char *buffer;
rmlock(my_stuff.news_dir, "history", "Unbatch");
rmlock(my_stuff.incoming_dir, batch_name, "Unbatch");
printf("\n\n");
printf("unbatch: A fatal error occurred, error #%d\n", numb);
printf(" %s\n", text);
printf(" errno is %d\n", errno);
buffer = strerror(errno);
printf(" %s\n\n", buffer);
printf("Unbatch did not complete successfully\n\n");
if (fcloseall() == EOF)
printf("Some files were not successfully closed\n\n");
exit(2);
}
/*----------------------------- Ending Stats -------------------------------*/
void end_stats()
{
fprintf(stderr, "unbatch: complete, %u articles, %u duplicates, %u via disk, %u junked\n",
article_count, duplicate_count, disk_cnt, junk_count);
fprintf(stderr, " Initial free memory %lu, minimum free memory %lu\n",
MaxFree, MinFree);
fprintf(stderr, " Memory used %lu largest article was %lu\n", MaxFree-MinFree,
LargestArt);
}
/*--------------------------- post article work file to all groups ----*/
LINES *post_to_groups(LINES * spool, FILE *spool_file)
{
FILE *out_file = NULL;
LINES *help;
static char nglist[512], junk_test[512];
long where;
ACTIVE *gp;
char *p;
int junk_flag; /* nz - junk to junk group */
int already_junked; /* nz - message already junked */
already_junked = 0;
nglist[0] = '\0';
if ((spool == NULL) && (spool_file == NULL))
return NULL;
if (strlen(newsgroups) != 0) {
if (verbose) {
if (art_length > 0)
fprintf(stderr, "%4.4u %5.5ld bytes, Message-ID: %s\n",
article_count, prev_art_length, msg_id);
else
fprintf(stderr, "%4.4u, Message-ID: %s\n", article_count, msg_id);
}
/* Check if we've already got this message from another feed */
/* Shouldn't happen with NNTP, but can do with UUCP or CIX */
if (find_msg_id(msg_id) == NULL) {
if (control_flag == TRUE)
strcpy(newsgroups, "Newsgroups: control");
strcpy(junk_test, newsgroups);
/* If junk flag set, step through newsgroups line to see if */
/* this article is to be posted to an active group. If so */
/* set already_junked to prevent crossposting to junk. */
if (!CrossPostToJunk) {
p = strtok(junk_test, " \t\r\n,:");
p = strtok(NULL, " \t\r\n,:");
while (p != '\0') {
gp = find_news_group(p, &junk_flag);
if (junk_flag == 0) { /* Posting to active group */
already_junked = 1; /* No need to post to junk */
break;
}
p = strtok(NULL, " \t\r\n,:");
}
strcpy(junk_test, newsgroups);
/* if omitting a group then don't place in nglist */
p = strtok(junk_test, " \t\r\n,:");
p = strtok(NULL, " \t\r\n,:");
if (already_junked == 0)
strcpy(nglist, newsgroups + 11);
else {
while (p != '\0') {
gp = find_news_group(p, &junk_flag);
if (junk_flag == 0)
strcat(nglist, p);
p = strtok(NULL, " \t\r\n,:");
if ((p != '\0') && (junk_flag == 0))
strcat(nglist, ",");
}
strcat(nglist, "\n");
}
}
else
strcpy(nglist, newsgroups + 11);
/* Step through the list of newsgroups */
p = strtok(newsgroups, " \t\r\n,:");
p = strtok(NULL, " \t\r\n,:");
/*
* For each newsgroup
* - open the text file
* - save the file pointer
* - append the message to it
* - close the file
* - open the index file
* - save the file pointer and the subject line
*/
if (verbose)
fputc('\t', stderr);
while (p != '\x00') {
out_file = open_out_file(p, &junk_flag);
if (verbose) {
if (junk_flag)
fprintf(stderr, " (%s)", p);
else
fprintf(stderr, " %s ", p);
}
if (junk_flag != 0) {
/* Check to see if we have already posted this in "junk". */
if (already_junked == 0) {
already_junked = 1;
junk_count++;
}
else {
/* Already posted in junk - skip it. */
if (fclose(out_file) == EOF) { /* skip this */
sprintf(buf, "closing %s", p);
abort_error(10, buf);
}
/* Reset the high message number. */
gp = find_news_group(p, &junk_flag);
(gp->hi_num)--;
update_active_entry(gp);
p = strtok(NULL, " \t\r\n,:"); /* next group */
continue;
}
} /* if (junk_flag != 0) */
where = ftell(out_file);
if (where == -1l) {
sprintf(buf, "getting pointer in %s", p);
abort_error(11, buf);
}
if (spool != NULL) {
for (help = spool; help != NULL; help = help->next)
if (fputs(help->data, out_file) == EOF) {
sprintf(buf, "writing to %s", p);
abort_error(12, buf);
}
}
else {
rewind(spool_file);
while (fgets(buf, 511, spool_file) != NULL)
if (fputs(buf, out_file) == EOF) {
sprintf(buf, "writing to %s", p);
abort_error(13, buf);
}
}
if (fprintf(out_file, "\n@@@@END\n") == EOF) {
sprintf(buf, "writing to %s", p);
abort_error(13, buf);
}
if (fclose(out_file) == EOF) {
sprintf(buf, "closing file %s", p);
abort_error(15, buf);
}
out_file = open_index_file(p);
gp = find_news_group(p, &junk_flag);
if (fprintf(out_file, "%08ld %08ld %09ld %s", where,
gp->hi_num, t, subject) == EOF) {
sprintf(buf, "writing to %s", p);
abort_error(16, buf);
}
if (fclose(out_file) == EOF) {
sprintf(buf, "closing %s", p);
abort_error(17, buf);
}
Free_Mem -= 3 * (sizeof(HIST_LIST)); /* account for history in memory */
p = strtok(NULL, " \t\r\n,:");
}
if (verbose)
fputc('\n', stderr);
add_hist_record(msg_id, nglist);
if (spool == NULL)
disk_cnt++;
}
else {
if (verbose)
fprintf(stderr, "\tDuplicate article\n");
duplicate_count++;
}
}
if (MinFree > farcoreleft())
MinFree = farcoreleft();
if (spool != NULL) {
while (spool) {
help = spool;
spool = spool->next;
free(help->data);
free(help);
}
}
else {
if (fclose(spool_file) == EOF)
abort_error(18, spool_name);
if (unlink(spool_name) == -1)
abort_error(19, spool_name);
spool_file = NULL;
}
return spool; /* == NULL */
}
/*--------------------------- unpack the batch ------------------------*/
void toss(FILE * tmp_file)
{
/*
* Toss it into the appropriate files.
*
*/
LINES *spool = NULL, *help;
FILE *spool_file = NULL;
char *p;
int /* already_junked, */ in_header;
int token, first_token;
int on_disk = 0;
char buf2[512];
strcpy(msg_id, "");
strcpy(subject, "-- no subject --\n");
strcpy(newsgroups, "");
rewind(tmp_file);
time(&t);
in_header = TRUE;
/* set a large disk transfer buffer */
/* read the file */
first_token = 0;
while (fgets(buf, 511, tmp_file) != NULL) {
if (!filter_mode)
remcr(buf);
else
filter(buf);
/*
* Check for a line containing only the Rnews token or rfc1036 style
* token + count.
* This is still liable to abuse but not so much so as accepting that
* token *anywhere* in the line, like it used to do.
*
* art_length is losely checked to see it the Rnews token is at the
* expected place in the file. If no the token is assumed to be part
* of an article.
*
* The test could still be made more secure (i.e. if the count is
* there, ensure nothing else follows it).
*/
token = 0;
prev_art_length = art_length;
if (prev_art_length > LargestArt)
LargestArt = prev_art_length;
if (strncmp(buf, "#! rnews", 8) == 0 &&
((strcspn(buf + 8, "\r\n") == 0) ||
((art_length = atol(buf + 8)) != 0l)))
token = 1; /* Token found */
if ((first_token == 0) && token == 1) {
art_start = ftell(tmp_file);
art_end_calc = art_start + art_length;
}
if (first_token != 0) {
if ((no_length == 0) && (token == 1) &&
(((art_end_calc + art_lines - 1) - 10) > art_end))
token = 0; /* Token not within 10 bytes of correct place */
}
else {
first_token = 1;
}
if (token == 1) {
art_start = ftell(tmp_file);
art_end_calc = art_start + art_length;
art_lines = 0l;
if ((art_length > Free_Mem) || (art_length == 0l) || (Via_Disk != 0))
on_disk = 1;
else
on_disk = 0; /* this one to 0 */
spool = post_to_groups(spool, spool_file);
spool_file = NULL;
article_count++;
strcpy(subject, "-- no subject --\n");
strcpy(newsgroups, "");
in_header = TRUE;
control_flag = FALSE;
}
else {
/* flag the end of the header */
if (strcmp(buf, "\n") == 0)
in_header = FALSE;
/* save the newsgroups line */
if (in_header) {
if (strnicmp(buf, "Message-ID:", 11) == 0) {
strcpy(msg, buf);
p = strtok(msg, " \t\r\n");
p = strtok(NULL, " \t\r\n");
strcpy(msg_id, p);
}
if ((strnicmp(buf, "Newsgroups:", 11) == 0) && (newsgroups[0] == '\0'))
strcpy(newsgroups, buf);
if (strnicmp(buf, "Control:", 8) == 0)
control_flag = TRUE;
if (strnicmp(buf, "Subject:", 8) == 0) {
if (strlen(buf) > 136) {
buf[136] = '\n';
buf[137] = '\0';
}
strcpy(subject, buf + 8);
}
/* add our system name to the path list */
if (strnicmp(buf, "Path:", 5) == 0) {
p = strtok(buf, " \t");
p = strtok(NULL, " \t");
sprintf(buf2, "Path: %s.%s!%s", my_stuff.my_site,
my_stuff.my_domain, p);
if (on_disk == 0) {
if (spool == NULL)
spool = help = (LINES *) malloc(sizeof(LINES));
else {
help->next = (LINES *) malloc(sizeof(LINES));
help = help->next;
}
help->next = NULL;
help->data = (char *) malloc(strlen(buf2) + 1);
strcpy(help->data, buf2);
}
else {
if (spool_file == NULL)
spool_file = fopen(spool_name, "w+b");
if (spool_file == NULL) {
sprintf(buf, "opening to %s", spool_name);
abort_error(20, buf);
}
if (fprintf(spool_file, "%s", buf2) == EOF) {
sprintf(buf, "writing to %s", spool_name);
abort_error(21, buf);
}
}
}
else {
if (on_disk == 0) {
if (spool == NULL)
spool = help = (LINES *) malloc(sizeof(LINES));
else {
help->next = (LINES *) malloc(sizeof(LINES));
help = help->next;
}
help->next = NULL;
help->data = (char *) malloc(strlen(buf) + 1);
strcpy(help->data, buf);
}
else {
if (spool_file == NULL)
spool_file = fopen(spool_name, "w+b");
if (spool_file == NULL) {
sprintf(buf, "opening file %s", spool_name);
abort_error(22, buf);
}
if (fprintf(spool_file, "%s", buf) == EOF) {
sprintf(buf, "writing to %s", spool_name);
abort_error(122, buf);
}
}
}
}
/* if (in_header) */
else {
if (on_disk == 0) {
if (spool == NULL)
spool = help = (LINES *) malloc(sizeof(LINES));
else {
help->next = (LINES *) malloc(sizeof(LINES));
help = help->next;
}
help->next = NULL;
help->data = (char *) malloc(strlen(buf) + 1);
strcpy(help->data, buf);
}
else {
if (spool_file == NULL)
spool_file = fopen(spool_name, "w+b");
if (spool_file == NULL) {
sprintf(buf, "opening file %s", spool_name);
abort_error(23, buf);
}
if (fprintf(spool_file, "%s", buf) == EOF) {
sprintf(buf, "writing to %s", spool_name);
abort_error(24, buf);
}
}
}
}
art_lines++;
art_end = ftell(tmp_file);
if (art_end == -1l)
abort_error(25, "seeking in temporary file");
}
/* process the last one */
spool = post_to_groups(spool, spool_file);
}
/*--------------------------- unpack the batch ------------------------*/
FILE *decode_batches(char *fn, int no_toss)
{
/*
* take the batch, strip off the !cunbatch, and feed the file to uncompress,
* the opened uncompressed file is returned
*/
FILE *out_file;
size_t bufsize;
if (no_toss)
return (NULL);
/* open the uncompressed */
if ((out_file = fopen(fn, "rb")) == NULL) {
(void) printf("unbatch: cannot open uncompressed file %s\n", fn);
return (NULL);
}
/* set a large disk transfer buffer */
for (bufsize = (size_t) 32768U;
setvbuf(out_file, NULL, _IOFBF, bufsize) != 0 && bufsize > 512;
bufsize /= 2)
/* do nothing */ ;
return (out_file);
} /* FILE *decode_batches (char *fn, int no_toss) */
/*------------------------- remove CR's from buffer ------------------------*/
void remcr(char *buf)
{
char *s, *d;
s = d = buf;
do {
if (*s != 0x0d)
*d++ = *s;
}
while (*s++ != '\0');
}
/*------------------- remove non printables from buffer --------------------*/
void filter(char *buf)
{
char *s, *d;
s = d = buf;
do {
if (*s != 0) {
if (*s < 0x20) /* Since BC is signed char will get >0x80 as well */
if ((*s != '\t') && (*s != '\n') && (*s != '\f') && (*s != '\r'))
*s = '?';
}
if (*s != 0x0d)
*d++ = *s;
}
while (*s++ != '\0');
}
/*------------------- Process any new groups in batch ----------------------*/
static NEW_GROUP *added, *added_first;
void proc_new(char *f, int t)
{
FILE *batch_file;
int junk_flag, already_junked, count, in_header;
char batch_name[80];
char buf[512], junk_test[512], nglist[512], *p;
size_t bufsize;
ACTIVE *gp;
fprintf(stderr, "\nChecking %s for new newsgroups...", f);
if (t == 1)
fprintf(stderr, "\nAny found will be added to the newsbase\n\n");
if (t == 2)
fprintf(stderr, "\nYou will be asked if you wish to add any found\n\n");
load_active_file();
free_ng();
strcpy(batch_name, my_stuff.incoming_dir);
strcat(batch_name, f);
if ((batch_file = fopen(batch_name, "r")) == NULL) {
fprintf(stderr, "Unable to open batch file %s for processing\n", f);
rmlock(my_stuff.incoming_dir, batch_name, "Unbatch");
exit(1);
}
for (bufsize = (size_t) 32768U;
setvbuf(batch_file, NULL, _IOFBF, bufsize) != 0 && bufsize > 512;
bufsize /= 2)
/* do nothing */ ;
added_first = NULL;
count = 0;
in_header = 0;
while (fgets(buf, 511, batch_file) != NULL) {
if (strnicmp(buf, "#! rnews", 8) == 0)
in_header = 1;
if (strcmp(buf, "\n") == 0)
in_header = 0;
if ((strnicmp(buf, "Newsgroups:", 11) == 0) && (in_header == 1)) {
if (verbose)
fprintf(stderr, "\rArticle %d", ++count);
already_junked = 0;
nglist[0] = '\0';
strcpy(junk_test, buf + 11);
if (!CrossPostToJunk) {
p = strtok(junk_test, " \t\n\r,:");
while (p != '\0') {
gp = find_news_group(p, &junk_flag);
if (junk_flag == 0) { /* posting to active group */
already_junked = 1;
break;
}
p = strtok(NULL, " \t\n\r,:");
}
}
strcpy(junk_test, buf + 11);
p = strtok(junk_test, " \t\n\r,:");
if (already_junked == 1) {
nglist[0] = '\0';
}
else {
while (p != '\0') {
gp = find_news_group(p, &junk_flag);
if (junk_flag != 0)
strcat(nglist, p);
p = strtok(NULL, " \t\n\r,:");
if ((p != '\0') && (junk_flag != 0))
strcat(nglist, ",");
}
}
p = strtok(nglist, " \t\r\n,:");
while (p != '\0') {
/* we now have a new newsgroup in p */
addnew(p);
p = strtok(NULL, " \t\n\r,:");
}
}
}
gp = gp; /* suppress BCC error message */
fclose(batch_file);
close_active_file();
putch('\n');
putch('\r');
listnew(t);
addem();
freeadd();
}
int addnew(char *p)
{
if (added_first != NULL) {
added = added_first;
if (stricmp(added->name, p) == 0)
return 0; /* In first place in table */
if (added->next != NULL) {
do {
added = added->next;
if (stricmp(added->name, p) == 0)
return 0; /* Already in table */
}
while (added->next != NULL);
}
}
/* if here p not in table */
if (added_first == NULL) {
added_first = (NEW_GROUP *) malloc(sizeof(NEW_GROUP));
if (added_first == NULL) {
fprintf(stderr, "unbatch: Out of memory.\n");
rmlock(my_stuff.news_dir, "history", "Unbatch");
rmlock(my_stuff.incoming_dir, batch_name, "Unbatch");
exit(1);
}
added_first->next = NULL;
added = added_first;
}
else {
while (added->next != NULL)
added = added->next;
added->next = (NEW_GROUP *) malloc(sizeof(NEW_GROUP));
if (added->next == NULL) {
fprintf(stderr, "unbatch: out of memory.\n");
rmlock(my_stuff.news_dir, "history", "Unbatch");
rmlock(my_stuff.incoming_dir, batch_name, "Unbatch");
exit(1);
}
added = added->next;
}
added->next = NULL;
strcpy(added->name, p);
added->answer = 0;
return 1; /* added */
}
void listnew(int t)
{
char ch;
added = added_first;
if (added == NULL)
return; /* none to list */
do {
fprintf(stderr, "\nNew Group \"%s\" ", added->name);
if (t == 2) {
fprintf(stderr, "Add (Y/N) ? ");
ch = getch();
putch(ch);
ch = tolower(ch);
if (ch != 'y')
added->answer = 1;
}
added = added->next;
}
while (added != NULL);
putch('\n');
putch('\r');
}
void addem(void)
{
int ret;
added = added_first;
if (added == NULL)
return;
do {
if (added->answer == 0) {
#ifdef ATARI
ret = spawnlpe(P_WAIT, "addgroup", "addgroup", added->name, NULL, environ);
#else
ret = spawnlp(P_WAIT, "addgroup.exe", "addgroup.exe", added->name, NULL);
#endif
if (ret == -1) {
fprintf(stderr, "\nError running \"addgroup %s\"\n", added->name);
}
}
added = added->next;
}
while (added != NULL);
putch('\n');
putch('\r');
}
void freeadd()
{
NEW_GROUP *next;
added = added_first;
if (added == NULL)
return;
do {
next = added->next;
free(added);
if (next != NULL) {
added = next;
}
}
while (next != NULL);
}
#ifndef __TURBOC__
#ifndef ATARI
unsigned long farcoreleft(void)
{
union _REGS inregs, outregs;
_heapmin();
inregs.h.ah = 0x48;
inregs.x.bx = 0xffff;
_intdos(&inregs, &outregs);
return (16l * (long)outregs.x.bx);
}
unsigned long testcoreleft(void)
{
union _REGS inregs, outregs;
inregs.h.ah = 0x48;
inregs.x.bx = 0xffff;
_intdos(&inregs, &outregs);
return (16l * (long)outregs.x.bx);
}
#endif
#endif